﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using BbsbWebService.Enums;
using System.Net.Sockets;
using System.Net;
using System.Threading;
using BbsbWebService.Repositories;
using System.Runtime.Serialization;
using System.IO;
using System.Xml;
using System.Runtime.Serialization.Json;
using BbsbWebService.Classes.Controllers;

namespace BbsbWebService.Classes.Plugins.Bbsb
{
    public class BbsbController : IController
    {
        #region Private Members

        private static readonly string RequestString = "BBSBWSRequest";
        private static readonly string ResponseString = "BBSBWSResponse";
        private static readonly int listeningPort = 53007;

        #endregion

        #region IController Members

        public void SendCommand(string command)
        {
            SendMessage(string.Format("D:{0}:E", command), 0xcf10);
        }

        #endregion

        public void SendRequest()
        {
            SendMessage(RequestString, listeningPort);
        }

        private void SendMessage(string message, int port)
        {
            try
            {
                try
                {
                    UdpClient client = new UdpClient();
                    IPEndPoint endPoint = new IPEndPoint(IPAddress.Broadcast, port);
                    byte[] bytes = Encoding.ASCII.GetBytes(message);
                    client.Send(bytes, bytes.Length, endPoint);
                    client.Close();
                }
                catch (Exception ex)
                {
                    Logging.Logger.Instance.LogException(ex, "Error sending command: '{0}'", message);
                }
            }
            catch (Exception ex)
            {
                System.Windows.Forms.MessageBox.Show(ex.Message);
            }
        }

        public void Listen()
        {
            Listening = true;
            ThreadPool.QueueUserWorkItem(o =>
                {
                    try
                    {
                        UdpClient _udpclient = new UdpClient(listeningPort, AddressFamily.InterNetwork);
                        _udpclient.EnableBroadcast = true;
                        IPEndPoint remoteEP = new IPEndPoint(IPAddress.Any, listeningPort);
                        byte[] receive_byte_array;
                        string received_data;
                        while (Listening)
                        {
                            if (_udpclient.Available > 0)
                            {
                                receive_byte_array = _udpclient.Receive(ref remoteEP);
                                received_data = Encoding.ASCII.GetString(receive_byte_array, 0, receive_byte_array.Length);
                                DecypherResponse(received_data);
                            }
                            Thread.Sleep(5);
                        }
                        _udpclient.Close();
                    }
                    catch (Exception ex)
                    {
                        Logging.Logger.Instance.LogException(ex, "Error listening on UDP port");
                    }
                });
        }

        public void StopListening()
        {
            Listening = false;
        }

        private void DecypherResponse(string response)
        {
            try
            {
                if (response.Contains("Button event"))
                {
                    try
                    {
                        string[] split = response.Split(' ');
                        string command = split[split.Length - 1];
                        RepositoryInstances.DecypherAndInterpret(command);
                    }
                    catch (Exception ex)
                    {
                        Logging.Logger.Instance.LogException(ex, "Invalid response decyphering: {0}", response);
                    }
                }
                else if (response.Equals(RequestString) && !ApplicationState.IsHuntingForServer)
                {
                    // send response...
                    DataContractJsonSerializer serialiser = new DataContractJsonSerializer(typeof(ServerItem));
                    MemoryStream stream = new MemoryStream();
                    serialiser.WriteObject(stream, ApplicationState.LocalMachine);
                    stream.Flush();
                    stream.Position = 0;
                    using (StreamReader reader = new StreamReader(stream))
                    {
                        string addressResponse = string.Format("{0};{1}", ResponseString, reader.ReadToEnd());
                        SendMessage(addressResponse, listeningPort);
                    }
                }
                else if (ApplicationState.IsHuntingForServer && response.StartsWith(ResponseString))
                {
                    // decypher response
                    string server = string.Empty;
                    string[] responses = response.Split(';');
                    if (responses.Length == 2)
                    {
                        DataContractJsonSerializer serialiser = new DataContractJsonSerializer(typeof(ServerItem));
                        MemoryStream stream = new MemoryStream(Encoding.UTF8.GetBytes(responses[1]));
                        object item = serialiser.ReadObject(stream);
                        if (item is ServerItem)
                        {
                            ApplicationState.ServerMachine = (ServerItem)item;
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                System.Windows.Forms.MessageBox.Show(ex.Message);
            }
        }

        public static bool Listening { get; set; }
    }
}
